﻿/*
This file is under Microsoft Public License (MS-PL)
Copyright Yohann MARTEL.  All rights reserved.
Codeplex: http://amf.codeplex.com
AMF Website: http://www.ymartel.com/aspnet-mobile-framework/
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Mobile.WebControls
{
    public class ListView : DataBoundControl
    {
        #region Events
        private static readonly object EventItemCreated = new object();
        private static readonly object EventItemDataBound = new object();
        #endregion

        #region Members
        private ITemplate itemTemplate;
        private ArrayList itemsArray;
        private RepeaterItemCollection itemsCollection;
        #endregion

        #region Properties
        [Category("Functionality")]
        public bool SearchEngine { get; set; }

        [Category("Functionality")]
        public bool IsNumberedList { get; set; }

        [Category("Separator Functionality")]
        public bool WithDataSeparator { get; set; }

        [Category("Separator Functionality")]
        public string SeparatorProperty { get; set; }

        [Category("Appearance")]
        public bool DataInset { get; set; }

        [Category("Appearance")]
        public DataTheme Theme { get; set; }

        [Category("Appearance")]
        public DataTheme SeparatorTheme { get; set; }

        /// <devdoc>
        ///    Gets the <see cref='System.Web.UI.WebControls.RepeaterItem'/> collection.
        /// </devdoc> 
        [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual RepeaterItemCollection Items
        {
            get
            {
                if (itemsCollection == null)
                {
                    if (itemsArray == null)
                    {
                        EnsureChildControls();
                    }
                    itemsCollection = new RepeaterItemCollection(itemsArray);
                }
                return itemsCollection;
            }
        }

        /// <devdoc>
        /// <para>Gets or sets the <see cref='System.Web.UI.ITemplate' qualify='true'/> that defines how items are rendered. </para> 
        /// </devdoc> 
        [Browsable(false),
            DefaultValue(null),
            PersistenceMode(PersistenceMode.InnerProperty),
            TemplateContainer(typeof(ListViewItem))]
        public virtual ITemplate ItemTemplate
        {
            get
            {
                return itemTemplate;
            }
            set
            {
                itemTemplate = value;
            }
        }

        /// <devdoc>
        /// <para> Occurs when an item is created within the <see cref='System.Web.UI.WebControls.Repeater'/> control tree.</para> 
        /// </devdoc>
        [Category("Behavior")
        ]
        public event ListViewItemEventHandler ItemCreated
        {
            add
            {
                Events.AddHandler(EventItemCreated, value);
            }
            remove
            {
                Events.RemoveHandler(EventItemCreated, value);
            }
        }


        /// <devdoc>
        /// <para>Occurs when an item is databound within a <see cref='System.Web.UI.WebControls.Repeater'/> control tree.</para>
        /// </devdoc> 
        [Category("Behavior")]
        public event ListViewItemEventHandler ItemDataBound
        {
            add
            {
                Events.AddHandler(EventItemDataBound, value);
            }
            remove
            {
                Events.RemoveHandler(EventItemDataBound, value);
            }
        }
        
        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }
        #endregion
        
        #region Methods
        /// <devdoc>
        /// <para>A protected method. Raises the <see langword='ItemCreated'/> event.</para> 
        /// </devdoc>
        protected virtual void OnItemCreated(ListViewItemEventArgs e)
        {
            ListViewItemEventHandler onItemCreatedHandler = (ListViewItemEventHandler)Events[EventItemCreated];
            if (onItemCreatedHandler != null) onItemCreatedHandler(this, e);
        }

        /// <devdoc>
        /// <para>A protected method. Raises the <see langword='ItemDataBound'/> 
        /// event.</para>
        /// </devdoc>
        protected virtual void OnItemDataBound(ListViewItemEventArgs e)
        {
            ListViewItemEventHandler onItemDataBoundHandler = (ListViewItemEventHandler)Events[EventItemDataBound];
            if (onItemDataBoundHandler != null) onItemDataBoundHandler(this, e);
        }

        protected override void CreateChildControls()
        {
            Controls.Clear();
            itemsArray = new ArrayList();
            ClearChildViewState();
        }

        protected override void PerformSelect()
        {

            // Call OnDataBinding here if bound to a data source using the
            // DataSource property (instead of a DataSourceID), because the
            // databinding statement is evaluated before the call to GetData.       
            if (!IsBoundUsingDataSourceID)
            {
                OnDataBinding(EventArgs.Empty);
            }

            // The GetData method retrieves the DataSourceView object from  
            // the IDataSource associated with the data-bound control.            
            GetData().Select(CreateDataSourceSelectArguments(),
                OnDataSourceViewSelectCallback);

            // The PerformDataBinding method has completed.
            RequiresDataBinding = false;
            MarkAsDataBound();

            // Raise the DataBound event.
            OnDataBound(EventArgs.Empty);
        }
        private void OnDataSourceViewSelectCallback(IEnumerable retrievedData)
        {

            // Call OnDataBinding only if it has not already been 
            // called in the PerformSelect method.
            if (IsBoundUsingDataSourceID)
            {
                OnDataBinding(EventArgs.Empty);
            }
            // The PerformDataBinding method binds the data in the  
            // retrievedData collection to elements of the data-bound control.
            PerformDataBinding(retrievedData);
        }

        protected override void OnDataBinding(EventArgs e)
        {
            base.OnDataBinding(e);

            // reset the control state
            Controls.Clear();
            ClearChildViewState();
        }

        protected override void PerformDataBinding(IEnumerable retrievedData)
        {
            base.PerformDataBinding(retrievedData);

            if (itemsArray != null)
            {
                itemsArray.Clear();
            }
            else
            {
                itemsArray = new ArrayList();
            }

            if (retrievedData != null)
            {
                ListViewItem item;
                int index = 0;

                string lastSeparatorName = null;
                foreach (object dataItem in retrievedData)
                {
                    //debug yo
                    if (WithDataSeparator)
                    {
                        object propertyValue = DataBinder.GetPropertyValue(dataItem, SeparatorProperty);
                        if (propertyValue != null)
                        {
                            SeparatorListViewItem separatorListViewItem = new SeparatorListViewItem();
                            if ((lastSeparatorName == null) || (lastSeparatorName != propertyValue.ToString()))
                            {
                                separatorListViewItem.Text = propertyValue.ToString();
                                Controls.Add(separatorListViewItem);
                                lastSeparatorName = propertyValue.ToString();
                            }
                        }
                    }
                    item = CreateItem(index, true, dataItem);
                    itemsArray.Add(item);
                }
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            EnsureDataBound();
            base.OnPreRender(e);
        }

        private ListViewItem CreateItem(int itemIndex, bool dataBind, object dataItem)
        {
            ListViewItem item = CreateItem(itemIndex);
            ListViewItemEventArgs e = new ListViewItemEventArgs(item);

            InitializeItem(item);
            if (dataBind)
            {
                item.DataItem = dataItem;
            }
            OnItemCreated(e);
            Controls.Add(item);

            if (dataBind)
            {
                item.DataBind();
                OnItemDataBound(e);

                item.DataItem = null;
            }

            return item;
        }

        protected virtual void InitializeItem(ListViewItem item)
        {
            ITemplate contentTemplate = itemTemplate;

            if (contentTemplate != null)
            {
                contentTemplate.InstantiateIn(item);
            }
        }

        /// <devdoc> 
        /// <para>A protected method. Creates a <see cref='System.Web.UI.WebControls.RepeaterItem'/> with the specified item type and
        ///    location within the <see cref='System.Web.UI.WebControls.Repeater'/>.</para> 
        /// </devdoc> 
        protected virtual ListViewItem CreateItem(int itemIndex)
        {
            return new ListViewItem(itemIndex);
        }
        #endregion

        #region Render Methods
        public override void RenderBeginTag(HtmlTextWriter writer)
        {
            AddAttributesToRender(writer);
            if (!IsNumberedList)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Ul);
            }
            else
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Ol);
            }
        }

        public override void RenderEndTag(HtmlTextWriter writer)
        {
            writer.RenderEndTag(); 
        }

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            writer.AddAttribute(MetadataAttribute.DataRole, DataRole.Listview);
            if (SearchEngine)
            {
                writer.AddAttribute(MetadataAttribute.DataFilter, Boolean.TrueString.ToLower());
            }
            if (DataInset)
            {
                writer.AddAttribute(MetadataAttribute.DataInset, Boolean.TrueString.ToLower());  
            }
            if (Theme != DataTheme.None)
            {
                writer.AddAttribute(MetadataAttribute.DataTheme, Enum.GetName(typeof(DataTheme), Theme).ToLower());
            }
            if (SeparatorTheme != DataTheme.None)
            {
                writer.AddAttribute(MetadataAttribute.DataDividerTheme, Enum.GetName(typeof(DataTheme), SeparatorTheme).ToLower());
            }

        }
        #endregion
    }
}
